package cnsukidayo.com.gitee.service.impl;

import cnsukidayo.com.gitee.exception.AuthenticationException;
import cnsukidayo.com.gitee.handler.properties.THPetContextProperties;
import cnsukidayo.com.gitee.mapper.PetMapper;
import cnsukidayo.com.gitee.mapper.PetShelterMapper;
import cnsukidayo.com.gitee.model.params.*;
import cnsukidayo.com.gitee.model.pojo.Pet;
import cnsukidayo.com.gitee.model.pojo.PetShelter;
import cnsukidayo.com.gitee.model.vo.PetShelterVO;
import cnsukidayo.com.gitee.service.PetShelterService;
import cnsukidayo.com.gitee.utils.Resources;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.abi.ABICodecException;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author sukidayo
 * @date 2023/3/26 10:08
 */
@Service
public class PetShelterServiceImpl implements PetShelterService {


    private final ConcurrentHashMap<String, Integer> petStoreToken = new ConcurrentHashMap<>();
    private final PetShelterMapper petShelterMapper;
    private final Client client;
    private final PetMapper petMapper;
    private BcosSDK bcosSDK;

    public PetShelterServiceImpl(PetShelterMapper petShelterMapper,
                                 Client client,
                                 PetMapper petMapper,
                                 BcosSDK bcosSDK) {
        this.petShelterMapper = petShelterMapper;
        this.client = client;
        this.petMapper = petMapper;
        this.bcosSDK = bcosSDK;
    }


    @Override
    public int login(LoginParam loginParam, HttpServletResponse httpServletResponse) {
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        Cookie cookie = new Cookie(THPetContextProperties.TOKEN, token);
        cookie.setMaxAge(30 * 24 * 60 * 60);
        cookie.setPath("/");
        httpServletResponse.addCookie(cookie);
        PetShelter petShelter = petShelterMapper.queryPetShelterByName(loginParam.getAccountName());
        if (!petShelter.getPassword().equals(loginParam.getPassword())) {
            throw new AuthenticationException("登陆失败,用户名或密码不正确");
        }
        petStoreToken.put(token, petShelter.getId());
        return petShelter.getId();
    }

    @Override
    public PetShelter getPetShelterInfo(int id) {
        return petShelterMapper.queryPetShelterById(id);
    }

    @Override
    public Optional<Integer> queryPetShelterIDByToken(String token) {
        return Optional.ofNullable(petStoreToken.get(token));
    }

    @Override
    public void addPetToShelter(Integer idReq, CreatePetParam createPetParam) {
        // 得到当前宠物收留所的ID
        PetShelter petShelterInfo = getPetShelterInfo(idReq);
        // 先查询到上一个数组的ID
        Integer id = petShelterMapper.queryMaxID();
//        KeyTool keyTool = new PEMKeyStore(new ByteArrayInputStream(petShelterInfo.getPublicKey().getBytes()));
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TransactionResponse getPetTransactionResponse = null;
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(createPetParam.getGender());
            // 调用PetShelter智能合约(创建宠物)
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetContract", THPetContextProperties.PET_CONTRACT, "addPet", params0);
            List<Object> params1 = new ArrayList<>();
            params1.add(id + 1);
            // 获取宠物的返回值并入库
            getPetTransactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetContract", THPetContextProperties.PET_CONTRACT, "getPet", params1);
        } catch (ABICodecException e) {
            throw new RuntimeException(e);
        } catch (TransactionBaseException e) {
            throw new RuntimeException(e);
        }
        // 插入宠物到数据库
        Pet insertPet = new Pet();
        insertPet.setCreateHash(getPetTransactionResponse.getTransactionReceipt().getTransactionHash());
        insertPet.setId((Integer) ((List) getPetTransactionResponse.getValuesList().get(0)).get(0));
        insertPet.setPetShelter(petShelterInfo.getId());
        // 交易地址就是宠物的地址
        petMapper.createPet(insertPet);
    }

    @Override
    public void addPetLog(String token, AddPetLogParam addPetLogParam) {
        Optional<Integer> petShelterID = queryPetShelterIDByToken(token);
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(addPetLogParam.getPetID());
            params0.add(petShelterID.get());
            params0.add(addPetLogParam.getLog());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "addPetLog", params0);
        } catch (ABICodecException e) {
            throw new RuntimeException(e);
        } catch (TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String queryPetLog(QueryPetLogParam queryPetLogParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TransactionResponse transactionResponse = null;
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(queryPetLogParam.getPetID());
            params0.add(queryPetLogParam.getShelterId());
            transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "getPetLog", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }
        return (String) transactionResponse.getValuesList().get(0);
    }

    @Override
    public void createPetShelter(CreatePetShelterParam createPetShelterParam) {
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        // 得到公钥
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getKeyPair().getPublic().getEncoded());
        // 得到私钥
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getKeyPair().getPrivate().getEncoded());
        // 得到地址
        String address = keyPair.getAddress();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TransactionResponse transactionResponse = null;
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(createPetShelterParam.getName());
            params0.add(createPetShelterParam.getAddress());
            transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "addPetShelter", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }
        PetShelter petShelter = new PetShelter();
        BeanUtils.copyProperties(createPetShelterParam, petShelter);
        petShelter.setAccountAddress(address);
        petShelter.setPublicKey(publicKey);
        petShelter.setPrivateKey(privateKey);
        petShelterMapper.insertPetShelter(petShelter);
    }

    @Override
    public List<PetShelterVO> queryPetShelterWithPage(QueryPageParam queryPageParam) {
        queryPageParam.setPageBegin((queryPageParam.getPageBegin() - 1) * queryPageParam.getPageSize());
        List<PetShelter> petShelters = petShelterMapper.queryPetShelterWithPage(queryPageParam);
        List<PetShelterVO> result = new ArrayList<>(petShelters.size());
        petShelters.forEach(petShelter -> {
            PetShelterVO petShelterVO = new PetShelterVO();
            BeanUtils.copyProperties(petShelter, petShelterVO);
            result.add(petShelterVO);
        });
        return result;
    }

    @Override
    public List<Pet> queryPetWithPage(PetQueryPageParam petQueryPageParam) {
        petQueryPageParam.setPageBegin((petQueryPageParam.getPageBegin() - 1) * petQueryPageParam.getPageSize());
        return petShelterMapper.queryPetWithPage(petQueryPageParam);
    }


    @Override
    public void purchaseSupplies(String token, PurchaseSuppliesParam purchaseSuppliesParam) {
        Optional<Integer> petShelterID = queryPetShelterIDByToken(token);
        CryptoKeyPair keyPair = client.getCryptoSuite().createKeyPair();
        AssembleTransactionProcessor transactionProcessor = null;
        try {
            transactionProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(client, keyPair, Resources.getResource("abi"), "");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            List<Object> params0 = new ArrayList<>();
            params0.add(petShelterID.get());
            params0.add(purchaseSuppliesParam.getAmount());
            params0.add(purchaseSuppliesParam.getEvent());
            transactionProcessor.sendTransactionAndGetResponseByContractLoader("PetShelterContract", THPetContextProperties.PET_SHELTER_CONTRACT, "purchaseSupplies", params0);
        } catch (ABICodecException | TransactionBaseException e) {
            throw new RuntimeException(e);
        }
    }

}
